//Copyright 2012 Trevin Liberty
//GNU GPL v3
//Author: Trevin Liberty

#include "Entity.h"

#include "../Structs.h"

void Entity::initEntity(short int strength, short int agility, float attackSpeed, float speed,
		float attackRange) 
{
	this->speed = speed;
	this->strength = strength;
	this->agility = agility;
	this->attackSpeed = attackSpeed;
	this->attackRange = attackRange;
	currentDestination = Point<int>(-1, -1);
	currentPath = new list<Point<int>>();

	currentMapCellPosition = getPosIndex();

	setIsAEntity();
}

void Entity::setPath(list<Point<int>>* p) {
	delete currentPath; 
	currentPath = p; 
	currentDestination = currentPath->front();
	currentPath->pop_front();
}

bool Entity::reachedGoal() {
	if(!hasGoal())
		return true;

	if(getPosIndex() == goal)
		return true;
	return false;
}

void Entity::setGoal(Point<int> goal) {
	//if out of range
	if(goal.x < 0 || goal.x >= map->numTilesX ||
		goal.y < 0 || goal.y >= map->numTilesY)
		return;

	//if not walkable
	if(!map->mapArray[goal.x][goal.y]->walkable) {
		return;
	}

	this->goal = goal;

	PathingQueueEntry* entry =  new PathingQueueEntry();
	entry->e = this;
	entry->start = getPosIndex();
	entry->dest = goal;

	aStar->addEntry(entry);
}

void Entity::updatePath() {
	if(reachedGoal()) {
		removeGoal();
		return;
	}

	if(shouldUpdatePath()) {
		PathingQueueEntry* entry =  new PathingQueueEntry();
		entry->e = this;
		entry->start = getPosIndex();
		entry->dest = goal;

		if(map->mapArray[goal.x][goal.y]->walkable) {
			aStar->addEntry(entry);
		}
	}

	//MAYBE A BOTTLENECK FOR ASTAR
	if(!aStar->isEmptyQueueOut()) {
		CompletedPath* path;
		path = aStar->queueOutGet(this);
		if(path != NULL)
			setPath(path->path);
	}
}

//If no path and haven't reached goal, return true
//If no path and have reached goal, return false
//If blocked for more than .75 seconds, return true
//If total block time is more than 3 seconds, return false AND remove goal
bool Entity::shouldUpdatePath() {
	//If no path
	if(currentPath->empty()) {
		firstBlockedTime = -1;
		blockedTime = -1;
		return false;
	}

	//If first blocked time is being tracked
	if(firstBlockedTime > 0) {
		//if the time is greater than 5 seconds
		//if true stop creating new path
		if((al_get_time() - firstBlockedTime) > 5) {
			currentPath->clear();
			removeGoal();
			firstBlockedTime = -1;
			blockedTime = -1;
			return false;
		}
	}

	//If current block is being tracked
	if(blockedTime > 0) {
		float timeMS = (al_get_time() - blockedTime);
		//if time is greater than .75 seconds
		//set blockedTime to current time
		//return true to create a new path
		if(timeMS > .25) {
			blockedTime = al_get_time();
			return true;
		}
	}

	return false;
}

void Entity::setBlocked() {
	if(blockedTime < 0)
		blockedTime = al_get_time();
	if(firstBlockedTime < 0)
		firstBlockedTime = al_get_time();
}

void Entity::setDirection(Point<float> vector) {
	vector.normalize();

	if(vector.x > .1) {
		if(vector.y > .1) {
			direction = SE;
		}
		else if(vector.y > -.1 && vector.y < .1) {
			direction = E;
		}
		else if(vector.y < -.1) {
			direction = NE;
		}
	}
	else if(vector.x > -.1 && vector.x < .1) {
		if(vector.y > .1) {
			direction = S;
		}
		else if(vector.y < -.1) {
			direction = N;
		}
	}
	else if(vector.x < -.1) {
		if(vector.y > .1) {
			direction = SW;
		}
		else if(vector.y > -.1 && vector.y < .1) {
			direction = W;
		}
		else if(vector.y < -.1) {
			direction = NW;
		}
	}
}

bool Entity::inRangeOfTarget() {
	if(target == NULL)
		return false;

	Point<int> p = this->getPosIndex();
	Point<int> tp = target->getPosIndex();

	float dist = sqrt(pow((p.x - tp.x), 2.0) + pow((p.y - tp.y), 2.0));

	if(dist <= attackRange)
		return true;

	return false;
}

Entity::~Entity() {
	aStar->removeEntityPaths(this);
	delete currentPath;
}